iT邦幫忙

2026 iThome 鐵人賽

DAY 5
0
自我挑戰組

賽博紓壓診所:從零打造純前端心理測驗與互動紓壓網頁系列 第 5

Day 05:SPA 單頁式應用架構:用原生 JS 控制畫面狀態與流暢切換

  • 分享至 

  • xImage
  •  

前言
在前幾天的文章裡,我們陸續把「賽博紓壓診所」的 HTML 骨架、CSS 變數、日夜模式以及呼吸燈過場動畫都刻出來了。

回想在 Day 02 提過的 SPA(Single Page Application,單頁式應用) 概念,這個專案從頭到尾都只在同一個 index.html 裡面運作。使用者不需要每次切換分頁就重新整理網頁。今天我們就要把這些零散的畫面區塊全部串起來,用純 JavaScript 打造一套乾淨、好擴充的畫面切換狀態機!

核心觀念:用 ClassList 管理畫面狀態
既然是單頁應用,最直覺的做法就是把每個頁面(首頁、過場、測驗、結果)都用<div class="card">包起來,並且預設除了首頁之外,其他區塊都加上 .hidden(display: none;`)藏起來。

當使用者點擊按鈕時,我們不需要透過後端路由跳轉,只需要透過 JavaScript 去動態操作 DOM 的 classList:把當前畫面的 hidden 加上去,同時把下一個畫面的 hidden 拿掉。這樣就能達成零延遲、超滑順的畫面切換體驗!

動手寫 Code(上):樣式設定
首先,我們在網頁的頭部標籤裡寫好基礎樣式,之後把首頁、呼吸燈過場、測驗畫面與結果報告這四大區的 HTML 結構完整搭建起來:

    [data-theme="dark"] {
        --bg-color: #121212;
        --card-bg: #1e1e1e;
        --primary-color: #64b5f6;
        --text-main: #e0e0e0;
        --text-muted: #9e9e9e;
    }

    body {
        font-family: 'Segoe UI', Microsoft JhengHei, sans-serif;
        background: var(--bg-color);
        color: var(--text-main);
        margin: 0;
        padding: 0;
        display: flex;
        justify-content: center;
        align-items: center;
        min-height: 100vh;
        transition: background 0.3s, color 0.3s;
    }

    .container {
        width: 100%;
        max-width: 600px;
        padding: 20px;
    }

    .card {
        background-color: var(--card-bg);
        border-radius: var(--border-radius);
        box-shadow: 0 12px 30px rgba(0, 0, 0, 0.15);
        padding: 30px;
        text-align: center;
        transition: background-color 0.3s;
    }

    .btn {
        background-color: var(--primary-color);
        color: white;
        border: none;
        border-radius: 50px;
        padding: 12px 30px;
        font-size: 1rem;
        cursor: pointer;
        width: 100%;
        margin-top: 10px;
    }

    .breathe-circle {
        width: 120px;
        height: 120px;
        background-color: #90caf9;
        border-radius: 50%;
        margin: 30px auto;
        display: flex;
        justify-content: center;
        align-items: center;
        color: white;
        font-weight: bold;
        animation: breatheAnimation 4s infinite ease-in-out;
    }

    @keyframes breatheAnimation {
        0% { transform: scale(1); background-color: #90caf9; }
        50% { transform: scale(1.3); background-color: #42a5f5; }
        100% { transform: scale(1.0); background-color: #90caf9; }
    }

    .hidden { display: none; }
</style>

動手寫 Code(下):用原生 JS 串起全站畫面狀態機
在網頁主體中放入四大區塊,並在最下方編寫狀態切換的 JavaScript 函式。我們把從首頁到過場、再到測驗與結果頁面的切換邏輯全部串聯起來:

<div class="container">
    
    <!-- 1. 首頁區塊 -->
    <div id="welcome-screen" class="card">
        <h1>🧠 賽博紓壓診所與解碼器</h1>
        <p>結合廟宇抽籤、能力雷達圖與惡搞處方籤的頂級心靈小工具。</p>
        <button class="btn" onclick="goToBreathe()">進入紓壓診所</button>
    </div>

    <!-- 2. 深呼吸過場區塊(預設隱藏) -->
    <div id="breathe-screen" class="card hidden">
        <h2>🧘 調整呼吸,放鬆心情</h2>
        <div class="breathe-circle" id="breathe-text">吸氣...</div>
        <button class="btn" onclick="startQuiz()">準備好了,開始解碼</button>
    </div>

    <!-- 3. 測驗區塊(預設隱藏) -->
    <div id="quiz-screen" class="card hidden">
        <h2 id="question-text">心理測驗進行中...</h2>
        <button class="btn" onclick="showResult()">看診斷報告</button>
    </div>

    <!-- 4. 結果報告區塊(預設隱藏) -->
    <div id="result-screen" class="card hidden">
        <h1>🏥 賽博病歷診斷報告</h1>
        <div style="font-size: 2rem; color: var(--primary-color); margin: 20px 0;">88%</div>
        <button class="btn" onclick="restartQuiz()">重新掛號測驗</button>
    </div>

</div>

<script>
    // 從首頁切換至呼吸過場畫面
    function goToBreathe() {
        document.getElementById('welcome-screen').classList.add('hidden');
        document.getElementById('breathe-screen').classList.remove('hidden');
    }

    // 從過場畫面進入正式測驗
    function startQuiz() {
        document.getElementById('breathe-screen').classList.add('hidden');
        document.getElementById('quiz-screen').classList.remove('hidden');
    }

    // 從測驗跳轉至結果報告頁面
    function showResult() {
        document.getElementById('quiz-screen').classList.add('hidden');
        document.getElementById('result-screen').classList.remove('hidden');
    }

    // 重置測驗並返回首頁
    function restartQuiz() {
        document.getElementById('result-screen').classList.add('hidden');
        document.getElementById('welcome-screen').classList.remove('hidden');
    }
</script>

開發小想法與設計巧思
在思考這個專題的架構時,我一直在想:「怎麼樣才能讓使用者在操作時覺得很流暢、沒有負擔?」

傳統網頁換頁常常伴隨著畫面閃爍或重新載入的等待感,但透過這種原生 SPA 的寫法,所有的畫面切換都在毫秒內完成。搭配前面幾天做的呼吸燈過場,不僅能給使用者一個緩衝、達到減壓的效果,也讓整個專案的結構變得非常清爽好維護。完全不需要引入複雜的前端框架,用最純粹的 JavaScript 就能達到很棒的互動體驗!

今日結語與明日預告
今日我們透過 JavaScript 的 classList 操作,順利把前幾天做好的零散頁面串成了完整的 SPA 單頁架構,讓整個診所的流程能夠流暢地跑起來。

明天 Day 06:使用者頭像與設定表單的資料狀態綁定,我們要來處理首頁的頭像選擇與 Email 輸入框,把使用者的個人化設定存起來,準備帶入後續的測驗結果中。我們明天見!


上一篇
Day 04:不依賴套件!用 CSS Animation 刻出流暢的呼吸燈過場動畫
下一篇
Day 06:使用者頭像與設定表單的資料狀態綁定
系列文
賽博紓壓診所:從零打造純前端心理測驗與互動紓壓網頁7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
lin1015
iT邦新手 5 級 ‧ 2026-09-19 18:32:34

用 hidden class 串起四個畫面,對新手來說比一開始就上框架容易理解很多。流程變長後,分散的切換函式可能漏藏某張卡片;你會考慮做一個 showScreen(id),統一保證同一時間只顯示一個畫面,並順便處理焦點嗎?

我要留言

立即登入留言